"""
网页操作，selenium基类
本文件存放了selenium基类的封装方法
"""
import time

import win32con
import win32gui
from selenium.common.exceptions import NoSuchElementException, TimeoutException
from selenium.webdriver import Chrome, ActionChains
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium import webdriver
from common.processingScreenshots import screenshots
from common.processingLog import log
from config import deriver_type


class OperateWebdrive:
    def __init__(self):
        self.deriver_type = deriver_type.lower()  # driver驱动类型

    def get_driver(self):
        """driver句柄"""
        if self.deriver_type == "chrome":
            self.driver = webdriver.Chrome()  # 谷歌浏览器驱动
        elif self.deriver_type == "ie":
            print("未配置ie浏览器驱动")  # ie浏览器驱动
        elif self.deriver_type == "firefox":
            print("未配置火狐浏览器驱动")  # 火狐浏览器驱动
        else:
            print("未获取驱动")
        return self.driver

    def get_url(self, url):
        """打开网页"""
        self.get_driver()
        self.driver.maximize_window()
        self.driver.set_page_load_timeout(60)  # 浏览器页面加载最长等待时间60s
        try:
            self.driver.get(url)
            self.driver.implicitly_wait(10)
            log.info("【打开网页】成功，网页地址：{}".format(url))
            return self.driver
        except TimeoutException as e:
            error = "【打开网页】失败，请检查网络或网址服务器，网页地址：{}".format(url)
            log.error(error)
            raise e

    def close_browser(self, defuse=None):
        """关闭浏览器"""
        time.sleep(1)
        self.driver.quit()
        time.sleep(2)
        log.info("【关闭浏览器】成功")

    def go_to_sleep(self, timeout=3):
        """等待"""
        try:
            timeout = int(timeout)
            time.sleep(timeout)
            log.info("【等待】结束")
        except Exception as e:
            error = "【等待】失败，输入的等待时间有误，请检查用例，错误信息：" + e
            log.error(error)
            raise e

    def get_element(self, locator):
        """查找单个元素
        :param locator:目标元素的定位
        :return: 目标元素可定位到则返回定位到的元素，否则报错
        """
        try:
            e = self.driver.find_element(*locator)
            log.info("【查找元素】成功，元素" + str(locator))
            return e
        except NoSuchElementException as e:
            screenshots(driver=self.driver)  # 截图
            log.error("【查找元素】失败，报错原因：" + str(e))  # 日志
            raise e

    def get_elements(self, locator):
        """查找多个相同元素
        :param locator:目标元素的定位
        :return: 目标元素可定位到则返回定位到的元素，否则报错
        """
        try:
            e = self.driver.find_elements(*locator)
            log.info("【查找元素】成功，元素" + str(locator))
            return e
        except NoSuchElementException as e:
            screenshots(driver=self.driver)  # 截图
            log.error("【查找元素】失败，报错原因：" + str(e))  # 日志
            raise e

    def element_num(self, locator):
        """获取相同元素的个数"""
        num = len(self.get_elements(locator))
        log.info("相同元素：{},共{}个".format(str(locator), num))
        return num

    # *******************************等待************************************************

    def wait_presence_element(self, locator, timeout=30, poll=0.2):
        """
        等待元素出现
        :param locator: 目标元素的定位
        :param timeout: 等待超时的时间
        :param poll: 循环查询的频率
        :return: 目标元素可定位到则返回定位到的元素，否则报错
        """
        try:
            e = WebDriverWait(driver=self.driver, timeout=timeout, poll_frequency=poll).until(
                EC.presence_of_element_located(locator=locator))
            log.info("【等待元素出现】成功，元素：" + str(locator))
            return e
        except TimeoutException as e:
            screenshots(self.driver)
            log.error("【等待元素出现】失败，报错原因：" + str(e))
            raise e

    def wait_clickable_element(self, locator, timeout=30, poll=0.2):
        """等待元素可点击
        :param locator: 目标元素的定位
        :param timeout: 等待超时的时间
        :param poll: 循环查询的频率
        :return: 目标元素可定位到则返回定位到的元素，否则报错
        """
        try:
            e = WebDriverWait(driver=self.driver, timeout=timeout, poll_frequency=poll).until(
                EC.element_to_be_clickable(locator=locator))
            log.info("【等待元素可点击】成功，元素：" + str(locator))
            return e
        except TimeoutException as e:
            screenshots(driver=self.driver)  # 截图
            log.error("【等待元素可点击】失败，报错原因：" + str(e))  # 日志
            raise e

    def wait_non_clickable_element(self, locator, timeout=30, poll=0.2):
        """等待元素不可点击
        :param locator: 目标元素的定位
        :param timeout: 等待超时的时间
        :param poll: 循环查询的频率
        :return: 目标元素可定位到则返回定位到的元素，否则报错
        """
        try:
            e = WebDriverWait(driver=self.driver, timeout=timeout, poll_frequency=poll).until_not(
                EC.element_to_be_clickable(locator=locator))
            log.info("【等待元素不可点击】成功，元素：" + str(locator))
            return e
        except TimeoutException as e:
            screenshots(driver=self.driver)  # 截图
            log.error("【等待元素可点击】失败，报错原因：" + str(e))  # 日志
            raise e

    def wait_visible_element(self, locator, timeout=30, poll=0.2):
        """
        等待元素可见
        :param locator: 目标元素的定位
        :param timeout: 等待超时的时间
        :param poll: 循环查询的频率
        :return: 目标元素可定位到则返回定位到的元素，否则报错
        """
        try:
            e = WebDriverWait(driver=self.driver, timeout=timeout, poll_frequency=poll).until(
                EC.visibility_of_element_located(locator=locator))
            log.info("【等待元素可见】成功，元素：" + str(locator))
            return e
        except TimeoutException as e:
            screenshots(self.driver)
            log.error("【等待元素可见】失败，报错原因：" + str(e))
            raise e

    def wait_invisible_element(self, locator, timeout=30, poll=0.2):
        """
        等待元素不可见
        :param locator: 目标元素的定位
        :param timeout: 等待超时的时间
        :param poll: 循环查询的频率
        :return: 目标元素可定位到则返回定位到的元素，否则报错
        """
        try:
            e = WebDriverWait(driver=self.driver, timeout=timeout, poll_frequency=poll).until_not(
                EC.visibility_of_element_located(locator=locator))
            log.info("【等待元素不可见】成功，元素：" + str(locator))
            return e
        except TimeoutException as e:
            screenshots(self.driver)
            log.error("【等待元素不可见】失败，报错原因：" + str(e))
            raise e

    # *******************检查点*****************************************************************
    def is_display_element(self, locator):
        """
        检查元素可见
        :param locator: 目标元素的定位
        :return: true或false，true为可见，false不可见
        """
        e = self.wait_visible_element(locator).is_displayed()
        return e

    def is_visible_element(self, locator):
        """
        检查元素可见
        :param locator: 目标元素的定位
        :return:
        """
        e = self.is_display_element(locator)
        if e:
            return True, "【检查元素可见】成功"
        else:
            return False, "【检查元素可见】失败"

    def is_invisible_element(self, locator):
        """
        检查元素不可见
        :param locator: 目标元素的定位
        :return:
        """
        e = self.is_display_element(locator)
        if e:
            return False, "【检查元素不可见】失败"
        else:
            return True, "【检查元素不可见】成功"

    def result_is_be_true(self, expected, title):
        """
        判断测试结果---------------不应该写着这个类中的，考虑移到哪吧
        :param expected: 期望结果的脚本，返回True则成功
        :param title: 测试用例的title
        :return:
        """
        try:
            assert expected == True
            print(title + "通过")
            log.info("【auto_test】——用例【{}】通过".format(title))
        except AssertionError as e:
            print(title + "失败")
            log.error("【auto_test】——用例【{}】未通过".format(title))
            raise e

    # *************************************************************************************

    def get_element_value(self, locator):
        """获取元素值"""
        e = self.wait_visible_element(locator)
        value = e.text
        return value

    def input(self, locator, data):
        """
        输入
        :param locator: 目标元素的定位
        :param data: 需要输入的值
        :return:
        """
        e = self.get_element(locator)
        try:
            e.send_keys(data)
            info = "【输入】成功，输入框对象：[{}]，输入值：[{}]".format(locator, data)
            log.info(info)
            return True, info

        except Exception as e:
            screenshots(self.driver)
            log.error("【输入】失败，报错原因：" + str(e))
            raise e

    def is_clear(self, locator):
        """
        清空输入框
        :param locator: 目标元素的定位
        :return:
        """
        self.get_element(locator).click()
        self.driver.implicitly_wait(0.5)
        log.info("【清空输入框】成功")

    def selector(self, locator, data):
        """
         下拉选择
         :param locator: 目标元素的定位
         :param data: 需要被选择的值
         :return:
         """
        e = self.get_element(locator)
        try:
            Select.select_by_value(data)
            log.info("【下拉选择】成功，选择框对象：[{}]，选择的值[{}]".format(locator, data))
        except Exception as e:
            screenshots(self.driver)
            log.error("【下拉选择】失败，报错原因：" + str(e))
            raise e

    def execute_script(self, script):
        """
        执行脚本
        :param script: jquery/javascript脚本
        :return:返回脚本执行后的结果
        """
        e_script = 'return ' + script
        time.sleep(2)
        e = self.driver.execute_script(script=e_script)
        log.info("【执行脚本】成功")
        return e

    # *******************************鼠标操作************************************************
    def click(self, locator):
        """
        鼠标操作--点击
        :param locator: 目标元素的定位
        :return:
        """
        e = self.wait_clickable_element(locator)
        e.click()
        log.info("【点击】成功，点击对象[{}]".format(locator))

    def double_click(self, locator):
        """
        鼠标操作--双击
        :param locator: 目标元素的定位
        :return:
        """
        e = self.wait_clickable_element(locator)
        action = ActionChains(self.driver)
        action.double_click(e).perform()
        log.info("【双击】成功，双击对象[{}]".format(locator))

    def context_click(self, locator):
        """
        鼠标操作--右击
        :param locator: 目标元素的定位
        :return:
        """
        e = self.wait_clickable_element(locator)
        action = ActionChains(self.driver)
        action.context_click(e).perform()
        log.info("【右击】成功，右击对象[{}]".format(locator))

    def move_to_element(self, locator):
        """
        鼠标操作--悬浮
        :param locator: 目标元素的定位
        :return:
        """
        e = self.wait_clickable_element(locator)
        action = ActionChains(self.driver)
        action.move_to_element(e).perform()
        log.info("【鼠标悬浮】成功，鼠标悬浮对象[{}]".format(locator))

    def drag_and_drop(self, source_locator, target_locator):
        """
        鼠标操作--把source_locator元素拖到target_locator中
        :param source_locator: 需要拖拽的元素
        :param target_locator: 放置拖拽元素的目标元素
        :return:
        """
        source = self.wait_clickable_element(source_locator)
        target = self.wait_presence_element(target_locator)
        action = ActionChains(self.driver)
        action.drag_and_drop(source=source, target=target).perform()
        log.info("【鼠标拖拽】成功，鼠标拖拽对象[{}]，放置的地方[{}]".format(source_locator, target_locator))

    def scroll_to_window_bottom(self, defuse=None):
        """滚动到窗口底部"""
        self.driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")
        log.info("【滚动到窗口底部】成功")

    # *******************************窗口操作************************************************

    def switch_window(self, action, timeout=30, poll=0.2):
        """
         切换浏览器窗口
         :param action: 切换窗口前的操作
         :param timeout: 等待超时的时间
         :param poll: 循环查询的频率
         :return:
         """
        window = self.driver.window_handles  # 操作前的窗口数量
        action  # 进行操作
        try:
            WebDriverWait(driver=self.driver, timeout=timeout, poll_frequency=poll).until(
                EC.new_window_is_opened(window))  # 等待新窗口打开
        except Exception as e:
            screenshots(self.driver)
            log.error("【切换浏览器窗口】失败，报错原因：" + str(e))
            raise e
        else:
            self.driver.switch_to.window(self.driver.window_handles[-1])  # 切换到新窗口
            log.info("【切换浏览器窗口】成功")

    def switch_to_iframe_window(self, locator, timeout=30, poll=0.2):
        """
        iframe窗口切换
        :param locator: 目标元素的定位
        :param timeout: 等待超时的时间
        :param poll: 循环查询的频率
        :return:
        """
        try:
            WebDriverWait(driver=self.driver, timeout=timeout, poll_frequency=poll).until(
                EC.frame_to_be_available_and_switch_to_it(locator=locator))
            log.info("【iframe窗口切换】成功")
        except Exception as e:
            screenshots(self.driver)
            log.error("【iframe窗口切换】失败，报错原因：" + str(e))
            raise e

    def switch_to_parent_iframe_window(self, defuse=None):
        """切换到iframe的上一层窗口"""
        try:
            self.driver.switch_to.parent_frame()
            log.info("【切换到iframe的上一层窗口】成功")
        except Exception as e:
            screenshots(self.driver)
            log.error("【切换到iframe的上一层窗口】失败，报错原因：" + str(e))
            raise e

    def switch_to_alert_window(self, defuse=None):
        """alert窗口切换"""
        try:
            self.driver.switch_to.alert
            log.info("【alert窗口切换】成功")
        except Exception as e:
            screenshots(self.driver)
            log.error("【切换alert窗口】失败，报错原因：" + str(e))
            raise e

    # *******************************************************************************

    def upload_file(self, file):
        """
        上传文件
        :param file: 需要被上传的文件
        :return: 
        """""
        dialog_class = "#32770"
        file_dir = file
        button_name = "打开(&O)"

        dialog = win32gui.FindWindow(dialog_class, "打开")

        ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, "ComboBoxEx32", None)  # 二级
        comboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, "ComboBox", None)  # 三级
        # 编辑按钮
        edit = win32gui.FindWindowEx(comboBox, 0, 'Edit', None)  # 四级
        # 打开按钮
        button = win32gui.FindWindowEx(dialog, 0, 'Button', button_name)  # 二级

        win32gui.SendMessage(edit, win32con.WM_SETTEXT, None, file_dir)  # 发送文件路径
        time.sleep(1)
        win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)  # 点击打开按钮

        # 成功的日志、失败的日志和截图
